#pragma once

#include <iostream>
#include <string>
#include <cassert>
#include <cstring>
#include <memory>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/wait.h>

#include "ThreadPool/log.hpp"
#include "ThreadPool/ThreadPool.hpp"
#include "ThreadPool/Task.hpp"

static void service(int sock, const uint16_t port, const std::string ip)
{
    char buffer[1024];
    while (true)
    {
        memset(buffer, 0, sizeof(buffer));
        // 这里使用read / write 接口直接对sock套接字进行读写数据即可
        ssize_t s = read(sock, buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            // 读取成功
            buffer[s] = 0;
            std::cout << ip << "[" << port << "]: " << buffer << std::endl;

            // 这里直接进行回显  ->   也可以其他方式来处理数据
            write(sock, buffer, strlen(buffer));
        }
        else if (s == 0)
        {
            // 对端关闭
            logMessage(NORMAL, "%s: %d shutdown, me too...", ip.c_str(), port);
            break;
        }
        else 
        {
            // 读取失败
            logMessage(FATAL, "read error, %d: %s", errno, strerror(errno));
            break;
        }
    }
    close(sock);
}

class Data
{
public:
    int sock;
    uint16_t port;
    std::string ip;
};

class TCP
{
    const static int gbacklog = 20;  // 全等待队列的大小

    static void* threadRoutine(void* argc)
    {
        pthread_detach(pthread_self());  // 进行线程分离,主线程无需等待子线程
        Data* src = (Data*)argc;
        service(src->sock, src->port, src->ip);
        delete src;
        return nullptr;
    }
public:
    TCP(uint16_t port, std::string ip = "0.0.0.0")
        :_port(port)
        ,_ip(ip)
        ,_listensock(-1)
        ,thread_ptr(ThreadPool<Task>::getThreadPool())  // 线程池进行初始化
    {}

    void initServer()
    {
        // 1.创建套接字
        _listensock = socket(AF_INET, SOCK_STREAM, 0);  // TCP以流的方式
        if (_listensock < 0)
        {
            logMessage(FATAL, "socker error, %d: %s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "socket success!");

        // 2.创建结构体, 进行bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = inet_addr(_ip.c_str());
        if (bind(_listensock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind error, %d: %s", errno, strerror(errno));
            exit(3);
        }
        logMessage(NORMAL, "bind success!");

        // 3.进行监听 listen
        if (listen(_listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen error, %d: %s", errno, strerror(errno));
            exit(4);
        }
        logMessage(NORMAL, "listen success!");
    }

    void start()
    {
        // 运行线程池
        thread_ptr->run();

        while (true)
        {
            // 1.先进行连接 accept
            struct sockaddr_in src;
            memset(&src, 0, sizeof(src));
            socklen_t len = sizeof(src);
            int servicesock = accept(_listensock, (struct sockaddr*)&src, &len);
            if (servicesock < 0)
            {
                logMessage(ERROR, "accept error, %d: %s", errno, strerror(errno));
                continue;
            }

            // 接受成功,可以拿出client的ip和port
            uint16_t client_port = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success, servicesock: %d | client_port: %d | client_ip: %s",
             servicesock, client_port, client_ip.c_str());

             // 2. 这里开始业务处理部分

            //  // v1.0 版本   ->  单进程循环版
            //  service(servicesock, client_port, client_ip);


            // // v2.0 版本  ->  多进程版本
            // pid_t pid = fork();
            // assert(pid != -1);
            // if (pid == 0)
            // {
            //     // 子进程
            //     close(_listensock);  // 子进程不用_listensock这个套接字就关闭它
            //     service(servicesock, client_port, client_ip);
            //     exit(0);
            // }
            // close(servicesock);  // 父进程不用servicesock,关闭它
            // waitpid(-1, nullptr, 0);


            // // v3.0 版本 -> 多线程版本
            // pthread_t tid;
            // Data* argc(new Data);
            // argc->sock = servicesock;
            // argc->port = client_port;
            // argc->ip = client_ip;
            // pthread_create(&tid, nullptr, threadRoutine, (void*)argc);


            // v4.0 版本  ->  线程池版本
            Task t(servicesock, client_ip, client_port, service);
            thread_ptr->PushTask(t);
        }
    }

    ~TCP()
    {}
private:
    std::string _ip;
    uint16_t _port;
    int _listensock;
    std::unique_ptr<ThreadPool<Task>> thread_ptr;
};
